package com.boot.aop;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.boot.dto.OperationLogDTO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class OperationLogAspect {

    private static final Logger log = LoggerFactory.getLogger("OPERATION_LOG");

    @Pointcut("execution(* com.boot.controller.*.*(..))")
    public void operationLog() {
    }

    @Around("operationLog()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) return joinPoint.proceed();

        HttpServletRequest request = attributes.getRequest();
        OperationLogDTO logDTO = new OperationLogDTO();
        long startTime = System.currentTimeMillis();

        // 设置基本信息
        logDTO.setMethod(request.getMethod());
        logDTO.setUri(request.getRequestURI());
        logDTO.setIp(getClientIP(request));
        logDTO.setTimestamp(java.time.LocalDateTime.now());

        // 获取请求参数（Query + Body）
        Map<String, Object> params = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (!parameterMap.isEmpty()) {
            parameterMap.forEach((key, value) -> params.put(key, value.length == 1 ? value[0] : value));
        }

        // 尝试获取 JSON Body（注意：只能读一次，需配合 requestBodyAdvice 处理重复读）
        Object requestBody = getRequestBody(joinPoint);
        if (requestBody != null) {
            params.put("body", requestBody);
        }
        logDTO.setRequestParams(params);

        // 执行方法
        Object result;
        try {
            result = joinPoint.proceed();
            logDTO.setStatus(200);
            logDTO.setResponseBody(result);
        } catch (Exception e) {
            logDTO.setStatus(500);
            logDTO.setResponseBody(e.getMessage());
            throw e;
        } finally {
            logDTO.setTakeTime(System.currentTimeMillis() - startTime);
            log.info(JSONUtil.toJsonStr(logDTO)); // 输出为 JSON 格式日志
        }

        return result;
    }

    private String getClientIP(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (StrUtil.isNotBlank(xForwardedFor) && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        String xRealIP = request.getHeader("X-Real-IP");
        if (StrUtil.isNotBlank(xRealIP) && !"unknown".equalsIgnoreCase(xRealIP)) {
            return xRealIP;
        }
        return request.getRemoteAddr();
    }

    private Object getRequestBody(ProceedingJoinPoint joinPoint) {
        for (Object arg : joinPoint.getArgs()) {
            if (arg != null && !arg.getClass().isPrimitive()
                    && !arg.getClass().getName().startsWith("java.")
                    && !(arg instanceof org.springframework.web.multipart.MultipartFile)) {
                return arg;
            }
        }
        return null;
    }
}
